﻿using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore.Metadata;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Cyss.Core.Repository
{
    /// <summary>
    /// Represents an entity repository
    /// </summary>
    /// <typeparam name="TEntity">Entity type</typeparam>
    public partial interface IRepository<TEntity> where TEntity : BaseEntity
    {

        TQueryableTable TableQueryable<TQueryableTable>();

        #region Methods

        /// <summary>
        /// 获取一条数据
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        TEntity GetById(object id);

        /// <summary>
        /// 插入一条数据
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="IsSubmit">是否立即提交</param>
        void Insert(TEntity entity, bool IsSubmit = true);

        /// <summary>
        /// 异步插入一条数据
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="IsSubmit">是否立即提交</param>
        /// <returns></returns>
        Task<int> InsertAsync(TEntity entity, bool IsSubmit = true);

        /// <summary>
        /// 插入多条数据
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="IsSubmit">是否立即提交</param>
        void Insert(IEnumerable<TEntity> entities, bool IsSubmit = true);

        /// <summary>
        /// 异步插入多条数据
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="IsSubmit">是否立即提交</param>
        /// <returns></returns>
        Task<int> InsertAsync(IEnumerable<TEntity> entities, bool IsSubmit = true);


        /// <summary>
        /// 更新一条数据
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="IsSubmit">是否立即提交</param>
        void Update(TEntity entity, bool IsSubmit = true);

        /// <summary>
        /// 异步更新一条数据
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="IsSubmit">是否立即提交</param>
        /// <returns></returns>
        Task UpdateAsync(TEntity entity, bool IsSubmit = true);

        /// <summary>
        /// 更新多条数据
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="IsSubmit">是否立即提交</param>
        void Update(IEnumerable<TEntity> entities, bool IsSubmit = true);

        /// <summary>
        /// 异步更新多条数据
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="IsSubmit">是否立即提交</param>
        /// <returns></returns>
        Task UpdateAsync(IEnumerable<TEntity> entities, bool IsSubmit = true);

        /// <summary>
        /// 大批量更新 默认更新所有除主键和自增建之外的所有字段
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <param name="entities"></param>
        /// <param name="keySelector">指定需要更新的字段 x => new { x.a, x.b } </param>
        void BulkUpdate<K>(IEnumerable<TEntity> entities, Expression<Func<TEntity, K>> keySelector = null);

        /// <summary>
        /// 大批量添加
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="DistinctKeySelector">判断是否重复的字段,重复的数据将不会添加</param>
        int BulkInsert(IEnumerable<TEntity> entities, Expression<Func<TEntity, object>> DistinctKeySelector = null);

        /// <summary>
        /// 大批量添加
        /// </summary>
        /// <param name="entities"></param>
        void BulkInsert(params IEnumerable<BaseEntity>[] entities);

        /// <summary>
        /// 删除一条数据
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="IsSubmit">是否立即提交</param>
        void Delete(TEntity entity, bool IsSubmit = true);

        /// <summary>
        /// 异步删除一条数据
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="IsSubmit">是否立即提交</param>
        /// <returns></returns>
        Task DeleteAsync(TEntity entity, bool IsSubmit = true);

        /// <summary>
        /// 删除多条数据
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="IsSubmit">是否立即提交</param>
        void Delete(IEnumerable<TEntity> entities, bool IsSubmit = true);

        /// <summary>
        /// 异步删除多条数据
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="IsSubmit">是否立即提交</param>
        /// <returns></returns>
        Task DeleteAsync(IEnumerable<TEntity> entities, bool IsSubmit = true);

        /// <summary>
        /// 根据表达式删除
        /// </summary>
        /// <param name="predicate"></param>
        void Delete(Expression<Func<TEntity, bool>> predicate);


        /// <summary>
        /// 判断属性值是否修改，如果是多个属性都修改才会返回true
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="ProNames"></param>
        /// <returns></returns>
        bool IsModified(TEntity entity, params string[] ProNames);

        /// <summary>
        /// 返回修改了的属性
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        IEnumerable<IProperty> GetModifiedProperties(TEntity entity);
        #endregion

        #region Properties

        /// <summary>
        /// 返回一个EF表
        /// </summary>
        IQueryable<TEntity> Table { get; }

        /// <summary>
        /// 获取一个启用了“无跟踪”（EF功能）的表。仅当您仅为只读操作加载记录时才使用该表
        /// </summary>
        IQueryable<TEntity> TableNoTracking { get; }

        #endregion

        #region EF扩展

        /// <summary>
        /// 根据主键删除一条数据
        /// </summary>
        /// <param name="Id"></param>
        void Delete(int Id);

        /// <summary>
        /// 根据主键值集合删除多条数据
        /// </summary>
        /// <param name="Ids"></param>
        void Delete(IEnumerable<int> Ids);

        /// <summary>
        /// 执行一条SQL语句
        /// </summary>
        /// <param name="sql"></param>
        /// <returns></returns>
        int ExecuteSqlCommand(string sql);

        /// <summary>
        /// 异步执行一条sql语句
        /// </summary>
        /// <param name="sql"></param>
        /// <returns></returns>
        Task<int> ExecuteSqlCommandAsync(string sql);

        /// <summary>
        /// 根据SQL获取数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Sql"></param>
        /// <param name="cmdParms"></param>
        /// <returns></returns>
        IEnumerable<T> Query<T>(string Sql, params SqlParameter[] cmdParms) where T : class, new();
        #endregion
    }
}
